home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / sdf.arc / SDF.ASM < prev    next >
Encoding:
Assembly Source File  |  1988-11-30  |  23.3 KB  |  975 lines

  1. Title 'SDF : Speedy Disk Formatter'
  2.  
  3. ; **************************************************************************
  4. ; * THIS PROGRAM IS PUBLIC DOMAIN. You Are Free To Use It And Redistribute *
  5. ; * It, As Long As No Profit Is Made Out Of It. Redistribution Costs May   *
  6. ; * Not Exceed $5. This Notice May Not Be Removed Or Altered In Any Way.   *
  7. ; * Use At Your Own Risk. Author Will Not Be Held Responsible For Any Dama-*
  8. ; * ge That Might Result Of Use Or Misuse. Enjoy.               *
  9. ; **************************************************************************
  10.  
  11. ; This program is inspired from QDR by Vernon D. Buerg, which unfortunately
  12. ; has a bug in handling 3.5" floppies.
  13.  
  14. ; Better late than never, I dedicate this program to Ward Christensen, who
  15. ; showed us the way in the good old CP/M days ...
  16.  
  17. ; Jacques Pierson, Belgrade (Belgium), November 1987.
  18. ; CIS 76446,1516
  19.  
  20. ;
  21. M24    =    0    ;set to one at work, for an Olivetti M24 (ATT 6300) 
  22. ;
  23. bell    equ    7
  24. bs    equ    8
  25. lf    equ    0Ah
  26. cr    equ    0Dh
  27. escape    equ    1Bh
  28. ulc    equ    0C9h    ;graphic char - Upper Left Corner
  29. llc    equ    0C8h    ;Lower Left Corner
  30. urc    equ    0BBh    ;Upper Right Corner
  31. lrc    equ    0BCh    ;Lower Right Corner
  32. vb    equ    0BAh    ;Vertical Border
  33. hb    equ    0CDh    ;Horizontal Border
  34. ;
  35. hsr    equ    0EFh    ;Head Step Rate : 4 ms
  36. hst    equ    0    ;Head Settle Time : 0 ms
  37. ;
  38.  
  39.  
  40. SDF    segment
  41.     assume ds:SDF, ss:SDF ,cs:SDF ,es:SDF
  42.  
  43.     org    0100h        ;make this a COM file
  44.  
  45.  
  46. start:    jmp    GetCmdLine
  47.  
  48. ; First describe our Disk Base Parms. We will make INT 1Eh to point here
  49. ; while formatting. Put at head of program so people without an assembler
  50. ; can easily patch this area w/ DEBUG.
  51.  
  52. OurDBP    equ    $
  53.  
  54.     db    hsr        ;high nibble : heads step rate
  55.                 ;low nibble, head unload time
  56.     db    2        ;DMA mode
  57.     db    255        ;clock ticks before stopping drive motor
  58.     db    2        ;sector size - 2 => 512 bytes
  59.     db    9        ;How many sectors per track
  60.     db    42        ;Gap length between sectors for R/W ops
  61.     db    -1        ;data length - Not used
  62.     db    80        ;Gap length when formatting
  63.     db    0F6h        ;Formatting char. Dos likes F6's
  64.     db    hst         ;Head settle time in ms.
  65.     db    1        ;Motor speed up time in 1/4 sec.
  66.  
  67. Welcome    db    cr,lf,'Speedy Disk Formatter, V1.0, '
  68.     db    '(c) Jacques Pierson, Nov 1987$'
  69.  
  70. UsageMessage    equ    $
  71.     db    cr,lf,lf,'Usage:  SDF drv: [switches]',cr,lf
  72.     db    'drv: mandatory and is either A: or B:,',cr,lf
  73.     db    'No switch => format standard 360K diskette, no verify',cr,lf
  74.     db    '/Q        => format Quad density (3',0abh,'" 720K disk)',cr,lf
  75.     db    '/V        => force Verify after format',cr,lf
  76.     db    'Multiple switches may be combined, e.g. SDF b:/q/v.'
  77.     db    cr,lf,lf,'$'
  78.  
  79. DriveMissing    db    cr,lf,lf,'Invalid or missing Drive Spec !$'
  80.  
  81. WrongSwitch    db    cr,lf,lf,'Unknown /switch in command line !$'
  82.  
  83. InsertDisk    db    cr,lf,lf,'Insert diskette in drive '
  84. Drive        db    'A, and press ENTER when ready ...$'
  85.  
  86. Again        db    cr,lf,lf,'Format complete,'
  87. Clusters    db    '      K available to user.'
  88.         db    cr,lf,'Press ENTER to format another diskette, '
  89.         db    'or ESCape to quit...$'
  90.  
  91. Formatting    db    cr,lf,lf,'Formatting '
  92. DiskType    db    'DSDD, Without$'
  93. Verify        db    ' Verify.',cr,lf,'$'
  94.  
  95. Track        db    cr,'Track: '
  96. TrackNr        db    '   Side: '
  97. SideNr        db    '   $'
  98.  
  99. ShowRetry    db    bs,'R$'
  100.  
  101. WritingBoot    db    ' - writing BOOT$'
  102. WritingFAT    db    ', FATs$'
  103. WritingDIR    db    ', DIR.$'
  104.  
  105. ErrorTbl    db    1,'Invalid command                '
  106.         db    2,'Address mark not found.        '
  107.         db    4,'Requested sector not found.    '
  108.         db    8,'DMA overrun on operation.      '
  109.         db    10h,'Bad CRC on diskette read/write.'
  110.         db    20h,'Controller failure.            '
  111.         db    40h,'SEEK operation failed.         '
  112. EndOfErrTbl    equ    $
  113.  
  114. FatalErr    db    bell,cr,lf,lf,'Door Open, Write-protected disk,'
  115.         db    ' or Drive Fails to respond.'
  116.         db    cr,lf,'Please fix problem and hit Enter to continue,'
  117.         db    'or ESCape to abort...$'
  118.  
  119. BadClusters    db    cr,lf,lf,'Bad sectors :'
  120. BadClNr        db    '       Cluster(s) disabled.',cr,lf,lf,'$'
  121. ;
  122. ErrBadSec    db    bs,bs,', Sec: '
  123. ErrSec        db    ' , Error '
  124. ErrCode        db    '   hex : '
  125. ErrMsg        db    'Unknown error.                 ',cr,lf,'$'
  126. ;
  127. ;
  128. ; Flags, set according to switches
  129. ;
  130. OptionsFlag    db    0    ;default is No Verify, Normal Disk
  131. CtrlBreak    db    0    ;Ctrl-Break flag on entry
  132. ;
  133. ; Disk characteristics, other parms are found in BootSector
  134. ;
  135. DirSecs        dw    7    ;DIRectory size in sectors
  136. DskTrks        db    40    ;Cyls/disk
  137. CurTrk        db    -1    ;Current track
  138. CurDrv        db    0    ;Current drive, binary, BIOS way (A:=0,..)
  139.  
  140.     even            ;Align for those w/8086 processors
  141.  
  142. RetryCount    dw    0    ;Count of retries
  143. MaxTries    dw    2    ;Maximum retries attempted
  144. BadSecCnt    dw    0    ;Count of Bad Sectors
  145. NextSec        dw    0    ;Temp storage for next sector #
  146. INT1Eoff    dw    0    ;INT 1Eh offset
  147. INT1Eseg    dw    0    ;INT 1Eh segment
  148. INT23off    dw    0    ;Ctrl-Break handler offset
  149. INT23seg    dw    0    ;Ctrl-Break segment
  150. ;
  151. HexTbl        db    '0123456789abcdef'
  152. ;
  153. ID_tbl    equ    $        ;table of ID's for track 0, side 0
  154. Side0        db    0,0,1,2
  155.         db    0,0,2,2
  156.         db    0,0,3,2
  157.         db    0,0,4,2
  158.         db    0,0,5,2
  159.         db    0,0,6,2
  160.         db    0,0,7,2
  161.         db    0,0,8,2
  162.         db    0,0,9,2        ;end of side 0
  163.  
  164. Side1        db    0,1,1,2        ;side 1 now
  165.         db    0,1,2,2
  166.         db    0,1,3,2
  167.         db    0,1,4,2
  168.         db    0,1,5,2
  169.         db    0,1,6,2
  170.         db    0,1,7,2
  171.         db    0,1,8,2
  172.         db    0,1,9,2        ;end of track, side 1
  173. ;
  174. ;
  175. ; Anatomy of our Boot sector
  176. ;
  177. BootSector    equ    $
  178.  
  179.         jmp    BootMsg
  180.  
  181.         db    'SDF  v01'    ;OEM name, 8 chars
  182.         dw    512        ;Sector size
  183.         db    2        ;Cluster size in sectors
  184.         dw    1        ;Reserved sectors
  185.         db    2        ;Number of FATs
  186. DirSize        dw    112        ;Directory entries
  187. TotSecs        dw    720        ;Total sectors
  188. MediaDes    db    0FDh        ;Media descriptor
  189. FatSize        dw    2        ;FAT size in sectors
  190.         dw    9        ;Sectors per Track
  191.         dw    2        ;Number of heads
  192.         dw    0        ;Number of hidden sectors
  193.         db    0        ;filler
  194.         db    0        ;head
  195.         db    10        ;length    of BIOS    file
  196.         db    hsr        ;The DPB, remember ?
  197.         db    2
  198.         db    25h
  199.         db    2
  200.         db    9
  201.         db    42
  202.         db    -1
  203.         db    80
  204.         db    0F6h
  205.         db    hst
  206.         db    1
  207.  
  208. NoBootMsg    equ    $
  209.  
  210.     db    cr,lf,lf
  211.     db    ulc,50 DUP (hb),urc,cr,lf
  212.     db    vb,'   This diskette has been formatted by SDF and    ',vb,cr,lf
  213.     db    vb,'    contains no system to boot from. Either       ',vb,cr,lf
  214.     db    vb,'  remove it and hit a key to boot from hard disk  ',vb,cr,lf
  215.     db    vb,'  if any, or replace it with another disk with a  ',vb,cr,lf
  216.     db    vb,'   system to boot from and hit a key when ready.  ',vb,cr,lf
  217.     db    llc,50 DUP (hb),lrc,cr,lf,lf,0
  218.  
  219.  
  220. BootMsg:
  221.     cli                ;no interrupts
  222.     cld                ;forward direction
  223.     mov    AX,07C0h        ;Boot runtime address
  224.     mov    DS,AX            ;to DS
  225.     mov    ES,AX
  226.     mov    SS,AX
  227.     mov    SP,0            ;temp stack at top of segment 
  228.     mov    SI,(OFFSET NoBootMsg - OFFSET BootSector) ;Msg ptr
  229. BNextChar:
  230.     lodsb                ;Get byte fm msg
  231.     or    AL,AL            ;a null ?
  232.     je    ReBoot            ;yes, print msg done
  233.     mov    AH,0Eh            ;print char, no bells and whistles
  234.     int    10h            ;Bios output char INT
  235.     jmp    SHORT BNextchar        ;loop for all string
  236. ;
  237. ReBoot:    xor    AH,AH            ;wait for key hit
  238.     int    16h
  239.  
  240.     int    19h            ;and try booting again 
  241.  
  242.  
  243. BEndOfStuff    equ    $
  244.  
  245.     db    (510 - (BEndOfStuff - BootSector)) DUP (0)    ;filler
  246.  
  247.     db    55h,0AAh        ;DOS disk signature
  248. ;
  249. ; End of boot sector
  250. ;
  251. ; First sector of File Allocation Table
  252. ;
  253. FatSec1    equ    $
  254.     db    0FDh            ;FAT - Media descriptor
  255.     db    0FFh
  256.     db    0FFh
  257.     db    509 DUP (0)        ;to get a full sector
  258.  
  259. FatSec2    db    512 DUP (0)        ;FAT, second sector
  260.     db    512 DUP (0)        ;FAT, third sector
  261. ;
  262. DirSec1    equ    $
  263. DskLbl    db    'SDF--------'        ;Dir entry for disk label, 11 char
  264.     db    28h            ;Attributes : Label + Archive
  265.     db    10 DUP (0)
  266. TimeLo    db    0
  267. TimeHi    db    0
  268. Date    dw    0
  269.     db    486 DUP (0)        ;full sector
  270. ;
  271. DirSec2    db    512 DUP (0)        ;2nd and other sectors
  272. ;
  273. ;
  274. ; Control-Break handler : DO NOT give user a chance to exit w/^C or Break
  275. ; without resetting the environement...
  276. ;
  277. ControlBreak: 
  278.  
  279.     iret                ;trap ^C and simply return
  280. ;
  281. ; Let's go to it now
  282. ;
  283. GetCmdLine:
  284.  
  285.     mov    DX,offset Welcome    ;print welcome msg
  286.     call    PrintString
  287.     mov    SI,80H            ;Peek at input bfr char count
  288.     lodsb                ;get byte
  289.     cbw                ;make word
  290.     or    AX,AX            ;any option ?
  291.     jne    GCL1            ;yes
  292. Usage:    mov    DX,offset UsageMessage
  293.     call    PrintString        ;Print and fall thru ErrorExit
  294. ;
  295. ; Error Exit, w/ return code 1, Normal Exit, w/ return code 0
  296. ;
  297. ErrorExit:
  298.     mov    AL,1
  299.     jmp    SHORT    DoExit
  300. ;
  301. Abort:    call    Restore            ;Restore INT 1E, INT 35
  302. ;
  303. Exit:    mov    AL,0            ;normal exit, no error
  304. DoExit:    mov    AH,4Ch            ;Program Exit
  305.     int    21h
  306. ;
  307. ;
  308. ; Carry on parsing command line
  309. ;
  310. GCL1:    mov    CX,AX            ;got something in cmd line, count to CX
  311.     call    ParseSwitches        ;Parse cmd line "/" switches
  312.     mov    SI,81h            ;Get drive spec
  313. GCL2:    lodsb
  314.     cmp    AL,' '            ;skip spaces
  315.     loopz    GCL2
  316.     jcxz    Usage            ;Nuts, give Usage Msg
  317.     cmp    AL,cr
  318.     jz    Usage
  319.     and    AL,5fh            ;Make drive letter uppercase
  320.     mov    Drive,AL        ;Put drive letter in msg
  321.     sub    AL,'A'            ;make binary, BIOS way
  322.     mov    CurDrv,AL        ;Store in current drive
  323.     cmp    AL,1            ;Drive MUST be 0 or 1
  324.     jg    BadDrive
  325.     lodsb
  326.     cmp    AL,':'            ;Make sure this WAS a drive spec
  327.     jne    BadDrive        ;no, it was not
  328.     jmp    Setup            ;Yes, indeed
  329. BadDrive:
  330.     mov    DX,OFFSET DriveMissing
  331.     call    PrintString
  332.     jmp    Usage
  333. ;
  334. ;
  335. A$Ret:    ret
  336. ;
  337. ; Parse command line switches
  338. ;
  339. ParseSwitches:
  340.     mov    DI,81h            ;peek at cmd line
  341. PS1:    mov    AL,'/'
  342.     repne    scasb            ;search for "/", length in CX
  343.     jne    A$Ret            
  344.     jcxz    A$Ret            ;none, or no more
  345.     mov    BYTE PTR [DI-1],cr    ;Got a "/", put a CR for later use
  346.     cmp    BYTE PTR [DI-2],' '    ;Previous char was space ?
  347.     jne    PS2            ;no
  348.     mov    BYTE PTR [DI-2],cr    ;yes, force to CR
  349. PS2:    mov    SI,DI
  350.     lodsb                ;get switch
  351.     and    AL,5Fh            ;Force uppercase
  352. PS3:    cmp    AL,'V'            ;/Verify ?
  353.     jne    PS4            ;no
  354.     mov    OptionsFlag,1        ;yes, remember that
  355.     mov    WORD PTR DskLbl+6,'V+'    ;put in disk label
  356.     mov    BYTE PTR DiskType+10,'$' ;truncate "Without" msg
  357.     jmp    PS1            ;parse next
  358. PS4:    cmp    AL,'Q'            ;/Quad density ?
  359.     jne    PS5            ;no, unknown switch
  360.     mov    BYTE PTR DiskType+2,'Q'    ;Flag, and Description
  361.     mov    DskTrks,80        ;80 tracks
  362.     mov    FatSize,3        ;FAT is 3 sectors long
  363.     mov    TotSecs,1440        ;1440 sectors
  364.     mov    MediaDes,0F9h        ;to Boot Sector
  365.     mov    WORD PTR DskLbl+8,'Q+'    ;put in disk label
  366.     jmp    PS1            ;parse next switch
  367. PS5:    mov    DX,OFFSET WrongSwitch
  368.     call    PrintString
  369.     jmp    Usage    
  370.  
  371. ;
  372. ; Restore : Restore the world as it was on entry
  373. ;
  374. Restore: lds    DX,DWORD PTR INT1Eoff    ;previous INT 1Eh vector
  375.     mov    AX,251Eh        ;restore it
  376.     int    21h
  377.  
  378.     mov    AH,0            ;Reset Disk System
  379.     int    13h
  380.  
  381.     lds    DX,DWORD PTR INT23off    ;Original DOS CtrlBreak handler
  382.     mov    AX,2523h        ;restore it
  383.     int    21h
  384.  
  385.     mov    AX,3301h        ;set Ctrl-Break flag
  386.     mov    DL,CtrlBreak        ;restore as was on entry
  387.     int    21h
  388.     ret
  389. ;
  390. ;
  391. ; Setup : Set up the world
  392. ;
  393. Setup:    mov    AH,AL            ;colon to AH
  394.     mov    AL,CurDrv
  395.     add    AL,'A'
  396.     mov    WORD PTR DskLbl+4,AX    ;put DriveSpec in disk label
  397.  
  398.     mov    AX,3300h        ;Get CtrlBreak flag
  399.     int    21h
  400.     mov    CtrlBreak,DL        ;save flag
  401.     mov    AX,3301h        ;set flag
  402.     xor    DL,DL            ;set checking OFF
  403.     int    21h
  404.  
  405.     push    DS
  406.     xor    AX,AX            ;point to low memory
  407.     mov    DS,AX
  408.     push    BX            ;Crazy MASM V.2 wants this..
  409.     mov    BX,(23h *4)        ;..whilst LDS SI,(23h*4) is perfectly
  410.     lds    SI,DWORD PTR [BX]    ;..legitimate to get INT 23h vector
  411.     pop    BX
  412.     mov    CS:INT23off,SI        ;store offset
  413.     mov    AX,DS
  414.     mov    CS:INT23seg,AX        ;store segment
  415.     pop    DS
  416.     mov    DX,OFFSET ControlBreak    ;our handler
  417.     mov    AX,2523h        ;Set Interrupt Vector 23h
  418.     int    21h
  419.  
  420.     push    DS
  421.     xor    AX,AX            ;point to low memory
  422.     mov    DS,AX
  423.     push    BX            ;MASM V.2 striking again !!
  424.     mov    BX,(1Eh * 4)
  425.     lds    SI,DWORD PTR [BX]    ;get INT 1E vector
  426.     pop    BX
  427.     mov    CS:INT1Eoff,SI        ;store offset
  428.     mov    AX,DS
  429.     mov    CS:INT1Eseg,AX        ;store segment
  430.     pop    DS
  431.     mov    DX,OFFSET OurDBP    ;our DBP
  432.     mov    AX,251Eh        ;Set Interrupt Vector 1Eh
  433.     int    21h
  434.     mov    AH,0            ;Reset Disk System
  435.     int    13h            ;our DBP is now in effect
  436.                     ;fall thru format loop
  437. ;
  438. Do_It:    mov    DX,OFFSET InsertDisk    ;say "Insert diskette in drive.."
  439.     call    PrintString
  440. ;
  441. GetChar:mov    AH,0            ;get char function
  442.     int    16h
  443.     cmp    AL,escape
  444.     jne    GC0
  445.     jmp    Abort
  446. GC0:    cmp    AL,cr
  447.     jne    GetChar            ;Escape or CR only !
  448.     mov    DX,OFFSET Formatting    ;"Formatting..."
  449.     call    PrintString
  450.     mov    DX,OFFSET Verify
  451.     call    PrintString
  452.     mov    BadSecCnt,0        ;no bad sector so far
  453.     call    PrepareFat
  454. ;
  455. ; Format all disk now
  456. ;
  457.     call    DoFormat        ;Here we go
  458.     mov    AX,BadSecCnt        ;any bad sector ?
  459.     or    AX,AX
  460.     je    NoBadSec        ;no
  461.     mov    SI,OFFSET BadClNr    ;Pointer to decimal places
  462.     call    AX2dec            ;convert to decimal
  463.     mov    DX,OFFSET BadClusters    ;Bad Clusters msg
  464.     call    PrintString    
  465. ;
  466. ; Write Boot, FAT, DIR
  467. ;
  468. NoBadSec:call    WriteBFD        ;write Boot, Fat, Dir
  469. ;
  470. ; Show available space
  471. ;
  472.     mov    AH,0Dh            ;reset disk system
  473.     int    21h
  474.     mov    AH,36h            ;get free space
  475.     mov    DL,CurDrv        ;for our drive
  476.     inc    DL            ;DOS way
  477.     int    21h
  478.     mov    AX,BX            ;clusters to AX
  479.     mov    SI,OFFSET Clusters
  480.     call    AX2dec            ;convert and fall thru print
  481. ;
  482. ; Done - prompt for another disk to format
  483. ;
  484.     mov    DX,OFFSET Again        ;"Hit enter to format another..."
  485.     call    PrintString
  486.     call    Whistle            ;Wake him up
  487.     jmp    GetChar            ;get char
  488.  
  489.  
  490. ;
  491. ; Prepare first FAT sector - This stuff required for multiple formatting
  492. ;
  493. PrepareFat:
  494.     sub    AX,AX            ;clear FAT to all zeros
  495.     mov    DX,FatSize        ;How many sectors ?
  496.     mov    DI,OFFSET FatSec1
  497. PF1:    mov    CX,512/2        ;sector size, in words
  498.     repz    stosw            ;for speed
  499.     dec    DX            ;next FAT
  500.     jnz    PF1
  501.     mov    AL,MediaDes        ;get Media Descriptor from Boot Sec
  502.     mov    BYTE PTR FatSec1,AL        ;move in place
  503.     mov    WORD PTR FatSec1+1,0FFFFh
  504.     ret
  505.  
  506. ;
  507. ; Here to REALLY format a disk
  508. ;
  509. DoFormat:
  510.     mov    CurTrk,-1        ;Initialize track nr
  511. NextTrk:                ;Prepare table for Track/sect. ID's
  512.     inc    CurTrk            ;Next track
  513.     mov    CH,CurTrk        ;to CH
  514.     cmp    CH,DskTrks        ;All done ?
  515.     jb    NT1            ;not yet
  516.     ret                ;yes, return
  517. NT1:    mov    DI,OFFSET ID_tbl    ;Point to table
  518.     mov    AL,18            ;18 sectors per Cyl
  519. NT2:    mov    [DI],CH            ;move Track # in table
  520.     add    DI,4            ;point to next entry
  521.     dec    AL            ;all done ?
  522.     jnz    NT2            ;No, loop
  523.     mov    AH,1            ;Give user a chance to abort
  524.     int    16h            ;Keyboard hit ?
  525.     jz    NT3            ;no
  526.     cmp    AL,escape        ;yes, Escape to abort ?
  527.     jne    NT3
  528.     jmp    Abort
  529. ;
  530. NT3:    mov    AX,0509h        ;Format Track, 9 sectors/trk
  531.     mov    BX,OFFSET Side0        ;track id table address, side 0
  532.     mov    DL,CurDrv        ;current drive
  533.     mov    DH,0            ;Side 0
  534.     mov    CL,1            ;First sec is #1
  535.     call    PrintProgress        ;Print progress (Track#, Side #)
  536.     int    13h            ;Format track, side 0
  537.     jnc    NT3V            ;No Carry, no error
  538.     call    Retry            ;Carry set, Shall we retry ?
  539.     jnc    NT3            ;yes, if we come here w/Carry clear
  540.                     ;else, give up
  541. NT3V:    test    OptionsFlag,1        ;Should we verify ?
  542.     jz    NT4            ;No, next side
  543. ;
  544. NT3R:    mov    AX,0409h        ;Verify, 9 sectors per track
  545.     int    13h
  546.     jnc    NT4            ;No carry, no error
  547.     call    Retry            ;Carry set, retry ?
  548.     jnc    NT3R            ;Yes, if Carry clear, else give up
  549. NT4:    mov    DH,1            ;Side 1
  550.     mov    AX,0509h        ;Format Track, 9 sectors/trk
  551.     mov    BX,OFFSET Side1        ;track id table address, side 1
  552.     mov    DL,CurDrv        ;current drive
  553.     mov    CL,1            ;First sec is #1
  554.     call    PrintProgress        ;Print progress (Track#, Side #)
  555.     int    13h            ;Format track, side 1
  556.     jnc    NT4V            ;no error
  557.     call    Retry            ;Carry set, error
  558.     jnc    NT4            ;Retry if Carry clear, else give up
  559. NT4V:    test    OptionsFlag,1        ;Should we verify ?
  560.     jz    NextTrk            ;no, next track
  561. ;
  562. NT4R:    mov    AX,0409h        ;Verify, 9 sectors per track
  563.     int    13h
  564.     jc    NT5            ;error !
  565.     jmp    NextTrk            ;no error, next track
  566. NT5:    call    Retry            ;Carry set, retry ?
  567.     jnc    NT4R            ;yes
  568.     jmp    NextTrk            ;no, next track
  569. ;
  570. Retry:    cmp    AH,3            ;Door open/Write protected ?
  571.     je    R1            ;yes
  572.     cmp    AH,80h            ;Attachment failed to respond ?
  573.     jne    R2            ;no, other error
  574. R1:    mov    DX,OFFSET FatalErr    ;tell him he'd better close the door
  575.     call    PrintString        ;..or remove the write-protect tab
  576.     pop    AX            ;clean up stack, we won't return
  577.     pop    AX            ;two calls to clean up
  578.     jmp    GetChar            ;OK, we may restart now
  579. R2:    push    DX
  580.     mov    DX,OFFSET ShowRetry    ;Show 'R' to indicate a retry
  581.     call    PrintString
  582.     pop    DX
  583.     inc    RetryCount
  584.     mov    DI,MaxTries        ;limit exceeded ?
  585.     cmp    RetryCount,DI
  586.     ja    SecIsBad        ;Yes, this one is really bad
  587.     mov    AH,0            ;No, Reset Disk System
  588.     int    13h
  589.     clc                ;clear carry
  590.     ret                ;and return to try again
  591. ;
  592. ; If we come here, we really have to deal with a bad sector
  593. ;
  594. SecIsBad: call    ShowBadSec
  595.     inc    BadSecCnt        ;count it
  596.     call    MarkBad            ;Mark whole cluster
  597.     mov    RetryCount,0        ;Reset retry count
  598.     stc                ;Set Carry to indicate "give up"
  599.     ret                ;go process next side or track
  600. ;
  601. ;
  602. ; Mark a bad sector (cluster) in FAT
  603. ;
  604. MarkBad:push    AX
  605.     push    BX
  606.     push    CX
  607.     push    DX
  608.     push    DI
  609.     push    SI
  610.     push    DS            ;We have to fetch..
  611.     mov    AX,40h            ;.. the faulty sector
  612.     mov    DS,AX            ;.. in the BIOS area
  613.     mov    BX,47h
  614.     mov    CL,BYTE PTR [BX]    ;Get sector number
  615.     pop    DS
  616.     mov    AL,CH            ;Track # to AL; AH is already 0
  617.     xor    CH,CH
  618.     cmp    DH,0            ;Side 0 ?
  619.     je    MB1
  620.     add    CL,9            ;Side 1, add 9 sects for side 0
  621. MB1:    shl    AX,1            ;* 2 heads
  622.     mov    BX,9            ;* 9 sectors per track
  623.     mul    BX            ;compute absolute sector #
  624.     add    AX,CX
  625.     sub    AX,FatSize        ;minus 1st FAT size
  626.     sub    AX,FatSize        ;minus 2nd FAT size
  627.     sub    AX,DirSecs        ;minus Directory size
  628.     mov    BL,2            ;disk heads
  629.     div    BX
  630.     add    AX,1
  631.     mov    CX,3
  632.     mul    CX
  633.     shr    AX,1            ; / 2
  634.     mov    DI,AX
  635.     lea    SI,[DI+FatSec1]        ;pointer into FAT
  636.     mov    DI,SI
  637.     lodsw                ;get cluster entry
  638.     mov    DX,0FF70h        ;12 bits, left aligned
  639.     jb    MB2            ;if even
  640.     mov    DX,0FF7h        ;if odd
  641. MB2:    or    AX,DX            ;merge w/ word to mark bad
  642.     stosw                ;store back in FAT
  643.     pop    SI
  644.     pop    DI
  645.     pop    DX
  646.     pop    CX
  647.     pop    BX
  648.     pop    AX
  649.     ret
  650. ;
  651. ; Write Boot sector, then FATs, then DIR.
  652. ;
  653. WriteBFD:
  654.     mov    DX,OFFSET WritingBoot
  655.     call    PrintString
  656.     mov    AL,CurDrv
  657.     lea    BX,BootSector        ;boot sector
  658.     mov    CX,1            ;1 sector to write
  659.     mov    DX,0            ;absolute sector 0
  660.     call    AbsSecWrite
  661. ;
  662. ; Write FAT(s)
  663. ;
  664.     push    DX            ;Preserve Sector Nr
  665.     mov    DX,OFFSET WritingFAT    ;"FATs"
  666.     call    PrintString
  667.     pop    DX
  668.     lea    BX,FatSec1        ;point to FAT 1st sector
  669.     mov    CX,1            ;1 sector write
  670.     inc    DX            ;DX knows which
  671.     mov    AL,CurDrv        ;current drive
  672.     call    AbsSecWrite
  673.     mov    CX,FatSize        ;sectors/FAT
  674.     dec    CX            ;One written already
  675.     lea    BX,FatSec2        ;get FAT 2nd sector
  676.     mov    AL,CurDrv        ;current drive
  677.     inc    DX            ;next sector(s)
  678.     call    AbsSecWrite
  679.     add    DX,CX            ;count sectors written this time
  680. ;
  681. ; Write second FAT
  682. ;
  683.     mov    AL,CurDrv        ;current drive
  684.     mov    BX,OFFSET FatSec1    ;FAT
  685.     mov    CX,1            ;1 sector, DX knows which
  686.     call    AbsSecWrite
  687.     mov    CX,FatSize        ;How many remaining ?
  688.     dec    CX            ;One already written
  689.     mov    BX,OFFSET FatSec2    ;point to FAT 2nd sector
  690.     mov    AL,CurDrv        ;current drive
  691.     inc    DX            ;next FAT sector(s)
  692.     call    AbsSecWrite
  693.     add    DX,CX
  694.     mov    NextSec,DX        ;remember next sector to write
  695. ;
  696. ; Write Directory
  697. ;
  698.     mov    DX,OFFSET WritingDIR    ;"DIRectory"
  699.     call    PrintString
  700. ;
  701. ; Update Disk Label Date and Time
  702. ;
  703.     mov    AH,2Ch            ;Get Time
  704.     int    21h
  705.     mov    BX,CX            ;Minutes, Seconds
  706.     mov    AX,CX
  707.     mov    CL,3
  708.     shl    CH,CL            ;Shift to move hour in place
  709.     shr    BL,CL            ;Shift to keep high 3 bits of min
  710.     add    CH,BL            ;merge
  711.     mov    TimeHi,CH        ;move in place
  712.     and    AL,7            ;keep min. lower 3 bits
  713.     shl    AL,1            ;shift
  714.     mov    CL,5
  715.     shr    DX,CL            ;Shift seconds
  716.     add    DH,AL            ;merge
  717.     mov    TimeLo,DH        ;move in place
  718.     mov    AH,2Ah            ;Get Date
  719.     int    21h
  720.     sub    CX,1980            ;From 1980 on
  721.     shl    CL,1
  722.     mov    BX,DX
  723.     mov    AH,CL
  724.     mov    CL,3
  725.     shr    DH,CL
  726.     add    AH,DH
  727.     mov    CL,5
  728.     shl    BH,CL
  729.     add    BH,DL
  730.     mov    AL,BH
  731.     mov    Date,AX            ;Move date in place
  732.     mov    AL,CurDrv        ;current drive
  733.     mov    BX,OFFSET DirSec1    ;First sector of DIR
  734.     mov    DX,NextSec        ;current sector
  735.     mov    CX,1            ;1 sector to write
  736.     call    AbsSecWrite
  737.     mov    AL,CurDrv
  738.     mov    BX,OFFSET DirSec2
  739.     mov    CX,DirSecs        ;How many sectors
  740.     dec    CX            ;One already written
  741. WD1:    push    CX
  742.     mov    CX,1            ;1 sector write
  743.     inc    DX            ;next one
  744.     call    AbsSecWrite
  745.     pop    CX            ;how many remaining ?
  746.     loop    WD1
  747.     ret                ;Done, next disk please.
  748. ;
  749. ; Print progress : Track nn Side n - inline decimal conversion
  750. ;
  751. PrintProgress:
  752.     push    AX
  753.     push    DX
  754.     mov    AL,DH            ;Side #
  755.     add    AL,'0'            ;Brute force ascify
  756.     mov    SideNr,al        ;Put side # in msg
  757.     mov    AL,CH            ;get track #
  758.     aam                ;THE trick
  759.     xchg    AL,AH            ;swap
  760.     add    AX,'00'            ;Ascify
  761.     mov    WORD PTR TrackNr,AX    ;Put track # in msg
  762.     mov    DX,OFFSET Track        ;say "Track..., Side..."
  763.     call    PrintString
  764.     pop    DX
  765.     pop    AX
  766.     ret
  767. ;
  768. ; Here to show that we have a bad sector
  769. ;
  770. ShowBadSec:
  771.     push    AX
  772.     push    BX
  773.     push    CX
  774.     push    DX
  775.     push    DI
  776.     push    SI
  777.     mov    DX,AX            ;Save AX for further hex printing
  778.     sub    BX,BX
  779.     mov    BL,AH            ;remember error code
  780.     mov    DI,OFFSET ErrorTbl    ;Table for INT 13 error codes & msgs
  781.     mov    AL,AH            ;Error code to AL
  782.     MOV    CX,OFFSET EndOfErrTbl
  783.     sub    CX,DI            ;compute table length
  784.     repnz    scasb            ;search for error code
  785.     jnz    SBS1            ;Not found, "Unknown Error"
  786.     mov    SI,DI            ;Got it, Ptr to SI
  787.     mov    CX,31            ;err msg length
  788.     mov    DI,OFFSET ErrMsg    ;Point to destination
  789.     repz    movsb            ;Move Err Msg in place
  790. SBS1:    mov    AL,DH            ;Get AH : error code
  791.     call    AL2hex            ;Convert
  792.     mov    WORD PTR ErrCode,AX    ;move AH (hex) in msg
  793.     push    DS
  794.     mov    AX,40h            ;Point to BIOS data area
  795.     mov    DS,AX
  796.     mov    BX,47h            ;the right place in BIOS area
  797.     mov    AL,BYTE PTR [BX]    ;BIOS knows which sector causes problem
  798.     pop    DS
  799.     add    AL,'0'            ;ascify
  800.     mov    ErrSec,AL        ;move sec # in msg
  801.     mov    DX,OFFSET ErrBadSec    ;give error msg
  802.     call    PrintString
  803.     pop    SI
  804.     pop    DI
  805.     pop    DX
  806.     pop    CX
  807.     pop    BX
  808.     pop    AX
  809.     ret
  810. ;
  811. ;
  812. ; AL2hex : binary AL to 2 hex digits in AX conversion
  813. ;
  814. AL2hex:    push    BX
  815.     push    CX
  816.     push    DX
  817.     push    SI
  818.     mov    BL,AL            ;will use BX as offset to tbl
  819.     mov    CL,4            ;bits to shift
  820.     sub    BH,BH
  821.     shr    BL,CL
  822.     and    AL,0Fh            ;mask off bits
  823.     sub    AH,AH
  824.     mov    SI,OFFSET HexTbl    ;point to hex tbl
  825.     add    SI,BX
  826.     mov    DL,[BX+HexTbl]
  827.     mov    BX,AX
  828.     mov    DH,[BX+HexTbl]
  829.     mov    AX,DX
  830.     pop    SI
  831.     pop    DX
  832.     pop    CX
  833.     pop    BX
  834.     ret
  835. ;
  836. ;
  837. ; AX2dec : routine to convert AX to decimal string at DS:SI
  838. ;
  839. AX2dec:    push    AX
  840.     push    CX
  841.     push    SI
  842.     xor    CL,CL            ;clear 10000 counter
  843. s10000:    inc    CL
  844.     sub    AX,10000
  845.     jnc    s10000
  846.     add    AX,10000        ;one SUB too much
  847.     add    CL,'0'-1        ;adjust and ascify
  848.     mov    [SI],CL            ;store in string
  849.     inc    SI
  850.     xor    CL,CL            ;clear 1000 counter
  851. s1000:    inc    CL
  852.     sub    AX,1000
  853.     jnc    s1000
  854.     add    AX,1000            ;one SUB too much
  855.     add    CL,'0'-1        ;adjust and ascify
  856.     mov    [SI],CL            ;store in string
  857.     inc    SI
  858.     xor    CL,CL            ;clear 100 counter
  859. s100:    inc    CL
  860.     sub    AX,100
  861.     jnc    s100
  862.     add    AX,100            ;one SUB too much
  863.     add    CL,'0'-1        ;adjust and ascify
  864.     mov    [SI],CL            ;store in string
  865.     inc    SI
  866.     aam                ;Convert value <100
  867.     xchg    AL,AH            ;swap
  868.     add    AX,'00'            ;Ascify
  869.     mov    [SI],AX
  870.     pop    SI            ;restore string ptr
  871.     mov    CX,5            ; 5 bytes to search
  872. AX2D1:    cmp    BYTE PTR [SI],'0'    ;leading Zero ?
  873.     jne    AX2D2            ;no or no more
  874.     mov    BYTE PTR [SI],' '    ;yes, make leading space
  875.     inc    SI
  876.     loop    AX2D1            ;loop for all
  877. AX2D2:    pop    CX
  878.     pop    AX
  879.     ret
  880. ;
  881. ;
  882. ; PrintString : print string pointed by DX, terminated by '$'
  883. ;
  884. PrintString:
  885.  
  886.     push    ax
  887.     mov    ah,9
  888.     int    21h
  889.     pop    ax
  890.     ret
  891. ;
  892. ; Absolute sector Write
  893. ;
  894. AbsSecWrite:
  895.  
  896.     push    AX
  897.     push    BX
  898.     push    CX
  899.     push    DX
  900.     int    26h            ;absolute sector write
  901.     jnb    ASW1            ;no carry, no error
  902.     xchg    CX,DX
  903.     mov    DH,DL
  904.     call    ShowBadSec
  905. ASW1:    popf
  906.     pop    DX
  907.     pop    CX
  908.     pop    BX
  909.     pop    AX
  910.     ret
  911. ;
  912. ; Absolute Sector Read 
  913. ;
  914. AbsSecRead:
  915.  
  916.     push    AX
  917.     push    BX
  918.     push    CX
  919.     push    DX
  920.     int    25h        ;absolute sector read
  921.     jnb    ASR1        ;no carry, no error
  922.     xchg    CX,DX
  923.     mov    DH,DL
  924.     call    ShowBadSec
  925. ASR1:    popf
  926.     pop    DX
  927.     pop    CX
  928.     pop    BX
  929.     pop    AX
  930.     ret
  931. ;
  932. ; Whistle - Wolf's whistle
  933. ;
  934. i8253    equ    40h        ;Timer chip base address
  935. i8255    equ    60h        ;PPI chip base address
  936. ;
  937. Whistle:
  938.     push    AX
  939.     mov    AL,0B6h        ;Counter 2, 2 bytes count, mode 3
  940.     out    (i8253+3),AL    ;Write Mode Word
  941.     mov    AX,1000        ;Divisor
  942.     push    AX
  943.     out    (i8253+2),AL    ;load lo byte
  944.     xchg    AH,AL
  945.     out    (i8253+2),AL    ;load hi byte
  946.     in    AL,(i8255+1)    ;8255, port B
  947.     or    AL,3        ;turn on bottom two bits, spkr on
  948.     out    (i8255+1),AL
  949.     pop    AX
  950. W1:    call    SwLoop        ;soft timing loop
  951.     dec    AX
  952.     out    (i8253+2),AL    ;load lo byte
  953.     xchg    AH,AL
  954.     out    (i8253+2),AL    ;load hi byte
  955.     xchg    AH,AL
  956.     jne    W1        ;loop
  957.     in    AL,(i8255+1)    ;8255, port B
  958.     and    AL,NOT 3    ;turn off bottom two bits, spkr off
  959.     out    (i8255+1),AL
  960.     pop    AX
  961.     ret
  962. ;
  963. ; Soft loop for Whistle
  964. ;
  965. SwLoop:    push    CX
  966.     mov    CX,100
  967. SWL:    loop    SWL
  968.     pop    CX
  969.     ret
  970. ;
  971.     SDF    ends
  972. ;
  973. end    start
  974.